/*
 * Copyright (c) Huawei Device Co., Ltd. 2023. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "session_proxy.h"

#include "common_utils.h"
#include "channel_proxy.h"
#include "loghelper.h"
#include "message_option.h"
#include "message_parcel.h"
#include "se_service_ipc_interface_code.h"

using namespace std;
namespace OHOS {
namespace SE {
namespace OMAPI {

ErrorCode SessionProxy::GetATR(std::string &atr)
{
    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);
    atr = std::string();
    if (!data.WriteInterfaceToken(GetDescriptor())) {
        ErrorLog("GetATR Write interface token error");
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    int32_t res = Remote()->SendRequest(static_cast<uint32_t>(SeServiceIpcInterfaceCode::COMMAND_SESSION_GET_ATR),
        data, reply, option);
    if (res != ERR_NONE) {
        ErrorLog("[SessionProxy::GetATR] send request(%{public}d) with Res(%{public}d) fail.",
            SeServiceIpcInterfaceCode::COMMAND_SESSION_GET_ATR, res);
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    InfoLog("[SessionProxy::GetATR] send request(%{public}d) with Res(%{public}d) success.",
        SeServiceIpcInterfaceCode::COMMAND_SESSION_GET_ATR, res);
    atr = reply.ReadString();
    int statusCode = reply.ReadInt32();
    return CommonUtils::IntToErrorCode(statusCode);
}

ErrorCode SessionProxy::Close(void)
{
    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);
    if (!data.WriteInterfaceToken(GetDescriptor())) {
        ErrorLog("Close Write interface token error");
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    int32_t res = Remote()->SendRequest(static_cast<uint32_t>(SeServiceIpcInterfaceCode::COMMAND_SESSION_CLOSE),
        data, reply, option);
    if (res != ERR_NONE) {
        ErrorLog("[SessionProxy::Close] send request(%{public}d) with Res(%{public}d) fail.",
            SeServiceIpcInterfaceCode::COMMAND_SESSION_CLOSE, res);
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    int statusCode = reply.ReadInt32();
    return CommonUtils::IntToErrorCode(statusCode);
}

ErrorCode SessionProxy::IsClosed(bool &isClosed)
{
    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);
    isClosed = true;
    if (!data.WriteInterfaceToken(GetDescriptor())) {
        ErrorLog("IsClosed Write interface token error");
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    int32_t res = Remote()->SendRequest(static_cast<uint32_t>(SeServiceIpcInterfaceCode::COMMAND_SESSION_IS_CLOSED),
        data, reply, option);
    if (res != ERR_NONE) {
        ErrorLog("[SessionProxy::IsClosed] send request(%{public}d) with Res(%{public}d) fail.",
            SeServiceIpcInterfaceCode::COMMAND_SESSION_IS_CLOSED, res);
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    InfoLog("[SessionProxy::IsClosed] send request(%{public}d) with Res(%{public}d) success.",
        SeServiceIpcInterfaceCode::COMMAND_SESSION_IS_CLOSED, res);
    isClosed = reply.ReadBool();
    int statusCode = reply.ReadInt32();
    return CommonUtils::IntToErrorCode(statusCode);
}

ErrorCode SessionProxy::CloseChannels(void)
{
    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);
    if (!data.WriteInterfaceToken(GetDescriptor())) {
        ErrorLog("CloseChannels Write interface token error");
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    int32_t res = Remote()->SendRequest(
        static_cast<uint32_t>(SeServiceIpcInterfaceCode::COMMAND_SESSION_CLOSE_CHANNELS), data, reply, option);
    if (res != ERR_NONE) {
        InfoLog("[SessionProxy::CloseChannels] send request(%{public}d) with Res(%{public}d) fail.",
            SeServiceIpcInterfaceCode::COMMAND_SESSION_CLOSE_CHANNELS, res);
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    int statusCode = reply.ReadInt32();
    return CommonUtils::IntToErrorCode(statusCode);
}

ErrorCode SessionProxy::OpenBasicChannel(const std::string& aid,
                                         uint8_t p2,
                                         sptr<ISecureElementChannel> &channelIface, std::string &apduResp)
{
    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);
    if (!data.WriteInterfaceToken(GetDescriptor())) {
        ErrorLog("OpenBasicChannel Write interface token error");
        channelIface = nullptr;
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    data.WriteString(aid);
    data.WriteInt32(p2);
    int32_t res = Remote()->SendRequest(static_cast<uint32_t>(
        SeServiceIpcInterfaceCode::COMMAND_SESSION_OPEN_BASIC_CHANNEL), data, reply, option);
    if (res != ERR_NONE) {
        InfoLog("[SessionProxy::OpenBasicChannel] send request(%{public}d) with Res(%{public}d) fail.",
            SeServiceIpcInterfaceCode::COMMAND_SESSION_OPEN_BASIC_CHANNEL, res);
        channelIface = nullptr;
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }

    sptr<OHOS::IRemoteObject> object = reply.ReadRemoteObject();
    int statusCode = reply.ReadInt32();
    apduResp = reply.ReadString();
    if (object == nullptr) {
        InfoLog("[SessionProxy::OpenBasicChannel] send request(%{public}d) with State(%{public}d) Empty.",
            SeServiceIpcInterfaceCode::COMMAND_SESSION_OPEN_BASIC_CHANNEL, statusCode);
        channelIface = nullptr;
    } else {
        channelIface = new (std::nothrow) ChannelProxy(object);
    }
    return CommonUtils::IntToErrorCode(statusCode);
}

ErrorCode SessionProxy::OpenLogicalChannel(const std::string& aid,
                                           uint8_t p2,
                                           sptr<ISecureElementChannel> &channelIface, std::string &apduResp)
{
    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);
    if (!data.WriteInterfaceToken(GetDescriptor())) {
        ErrorLog("OpenLogicalChannel Write interface token error");
        channelIface = nullptr;
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    data.WriteString(aid);
    data.WriteInt32(p2);
    int32_t res = Remote()->SendRequest(
        static_cast<uint32_t>(SeServiceIpcInterfaceCode::COMMAND_SESSION_OPEN_LOGIC_CHANNEL), data, reply, option);
    if (res != ERR_NONE) {
        InfoLog("[SessionProxy::OpenLogicalChannel] send request(%{public}d) with Res(%{public}d) fail.",
            SeServiceIpcInterfaceCode::COMMAND_SESSION_OPEN_LOGIC_CHANNEL, res);
        channelIface = nullptr;
        return ErrorCode::SE_IPC_TOKEN_ERROR;
    }
    sptr<OHOS::IRemoteObject> object = reply.ReadRemoteObject();
    int statusCode = reply.ReadInt32();
    apduResp = reply.ReadString();
    if (object == nullptr) {
        InfoLog("[SessionProxy::OpenLogicalChannel] send request(%{public}d) with state(%{public}d) Empty.",
            SeServiceIpcInterfaceCode::COMMAND_SESSION_OPEN_LOGIC_CHANNEL,
                statusCode);
        channelIface = nullptr;
    } else {
        channelIface = new (std::nothrow) ChannelProxy(object);
    }
    return CommonUtils::IntToErrorCode(statusCode);
}
}  // namespace OMAPI
}  // namespace SE
}  // namespace OHOS